#include <iostream>
#include "bigint.h"

using namespace std;

int bigint::sizeofchar(char* chr_arr)
{
	char chr = '1';
	int i = 0;
	while(chr > 47 && chr < 58)
	{
		chr = chr_arr[i];
		++i;
	}
	return i-1;
}

bigint::bigint()
{
#if __DEBUG
	cout << "Init big int" << endl;
#endif
}
void bigint::testHalfAddr(int xbit, int ybit)
{
	this->xbit = xbit;
	this->ybit = ybit;
	halfaddr();
}
void bigint::testFullAddr(int xbit, int ybit, int cbit)
{
	this->xbit = xbit;
	this->ybit = ybit;
	this->incbit = cbit;
	fulladdr();
}
int bigint::getSbit()
{
	return this->sbit;
}
int bigint::getCbit()
{
	return this->cbit;
}
void bigint::halfaddr()
{
	int cbit;
	int sbit;
	int xbit;
	int ybit;
	xbit = this->xbit;
	ybit = this->ybit;
	int notcbit;
	__asm{
			mov	eax, xbit
			and	eax, ybit
			mov cbit, eax				;cbit = xbit AND ybit
			
			mov	ebx, cbit
			mov	notcbit, ebx
			not	notcbit					;notcbit = NOT cbit
			mov	eax, xbit
			or	eax, ybit
			and	eax, notcbit
			mov	sbit, eax				;sbit = (xbit OR ybit) AND notcbit
	}
	this->cbit = cbit;
	this->sbit = sbit;
}
void bigint::fulladdr()
{
	int cbit;
	int cbit1;
	int sbit;
	int xbit = this->xbit;
	int ybit = this->ybit;
	int incbit = this->incbit;
	halfaddr();
	cbit = this->cbit;
	sbit = this->sbit;
		__asm {
			mov	ebx, cbit
			mov cbit1, ebx				;cbit1 = cbit
			
			mov ebx, sbit
			mov xbit, ebx				;xbit = sbit
			
			mov ebx, incbit
			mov ybit, ebx				;ybit = incbit
		}
		this->xbit = xbit;
		this->ybit = ybit;
		halfaddr();
		cbit = this->cbit;
		__asm {
			;call halfaddr				;halfaddr(xbit, ybit)
			
			mov ebx, cbit
			or ebx, cbit1
			
			mov cbit, ebx				;cbit = cbit OR cbit1
	}
		this->cbit = cbit;
}
int bigint::length()
{
	int sze = 0;
	int lng = this->num.size();
	int * arr = this->getNumber();
	__asm {
		mov ecx, lng
		mov eax, lng
		mov edx, 4
		mul edx
		sub eax, 4
		mov ebx, eax
		mov eax, arr
		mov edx, 0
lpcnt:
		cmp edx, [eax+ebx]
		jne lpcnt2
		dec ebx
		dec ebx
		dec ebx
		dec ebx ;is dec 4 faster than sub 4?
				;who knows?
		loop lpcnt
lpcnt2:
		mov ecx, 4
		mov eax, ebx
		div ecx
		inc eax
		mov sze, eax
	}
	/*for(int i = this->num.size() -1; i > 0; i--)
	{
		if (num[i] != 0)
		{
			size = i;
			break;
		}
	}*/
	delete arr;
	return sze;
}
int* bigint::getNumber()
{
	int* tmp; //I hope the caller remembers to delete this! ):
	tmp = new int[this->num.size()+2];
	for(int i = 0; i < (int)this->num.size(); i++)
		tmp[i] = this->num[i];
	return tmp;
}
int bigint::isnum(int n)
{
	if (n > 0)
		return n;
	else
		return 0;
}
bigint bigint::operator+(bigint& num)
{
	bigint ret;
	int* src_n = this->getNumber();
	int* src2_n = num.getNumber();
	int nsize = 0;
	//int lng = (this->length() > num.length()) ? (num.length()) : (this->length());
	//int lngarr = (this->length() < num.length()) ? (num.length()) : (this->length());
	//int * dest = new int[lngarr+1];
	int carry = 0;
	if (this->length() > num.length())
	{
		for (int i = 0; i < num.length() + 1; ++i)
		{
			src_n[i] = src_n[i] + this->isnum(src2_n[i]) + carry;
			carry = 0;
			if (src_n[i] >= 10)
			{
				src_n[i] -= 10;
				carry = 1;
			}
		}
		int n = this->length();
		if (this->length() < num.length())
			src2_n[n] += carry;
		else
			src2_n[n] = carry;
		//src_n[n] += carry;
		char * tmp;
		tmp = new char[this->num.size()+1];
		int x = 0;
		if (carry)
			nsize = this->num.size();
		else
			nsize = this->num.size() - 1;
		for (int i = nsize; i >= 0; --i) //reverse, reverse!
		{
			tmp[x] = src_n[i] + 48;
			++x;
		}

		ret.equals(tmp);
		delete tmp;
		//this->num.clear();

	} else {
		for (int i = 0; i < this->length() + 1; ++i)
		{
			src2_n[i] = this->isnum(src_n[i]) + src2_n[i] + carry;
			carry = 0;
			if (src2_n[i] >= 10)
			{
				src2_n[i] -= 10;
				carry = 1;
			}
		}
		int n = num.length();
		if (this->length() > num.length())
			src2_n[n] += carry;
		else
			src2_n[n] = carry;
		char * tmp;
		tmp = new char[num.num.size()+1];
		int x = 0;
		if (carry)
			nsize = num.num.size();
		else
			nsize = num.num.size() - 1;

		for (int i = nsize; i >= 0; --i) //reverse, reverse!
		{
			tmp[x] = src2_n[i] + 48;
			++x;
		}
		ret.equals(tmp);
		delete tmp;
		//num.num.clear();
	}
	//dest[lng] += carry;
	//for (int i = 0; i < (int)num.num.size(); i++)
	//	cout << src2_n[i];
	//delete dest;
	delete [] src_n;
	delete [] src2_n;
	return ret;
}
void bigint::equals(char* cn)
{
	this->num.clear();
	//cout << this->sizeofchar(chr_arr) << endl;
	//int nDigits = this->sizeofchar(chr_arr);
	int i;
	//pushback(num);
	//we have to do this in reverse
	__asm {
		;push num
		push cn
		mov ecx, this
		call bigint::sizeofchar
		mov ecx, eax
		mov i, ecx
		dec i
lpprep:
		/*
			We need to use assembly here to convert a ASCII number to an actual number
		*/
		;char_tmp[0] = chr_arr[i];
		;lea ax, char_tmp[0]
		mov eax, cn
		sub edx, edx
		mov ebx, i
		mov dl, [eax+ebx]
		sub dl, 48
		;mov num, edx
			//ints are 4?
		;mov eax, edx
		//need to push ecx BEFORE you push the number, right?
		push ecx
		push edx
		mov ecx, this
		call	bigint::pushback
		pop ecx
		dec i
		;push ecx
		//num = atoi(char_tmp[0]);
		//pushback(num);
		;pop ecx
		;push ecx
		loop lpprep
		;pop ecx
	}
	/*for(int i = nDigits-1; i >= 0; --i)
	{
		char_tmp[0] = chr_arr[i];
		num = atoi(char_tmp);
		this->num.push_back(num);
	}*/
	//return *this;
}
ostream& operator<<(ostream& os,bigint& bi)
{
	int size = bi.num.size();
	int* asm_bi;
	asm_bi = new int[size];
	for (int x = 0; x < size; ++x)
		asm_bi[x] = bi.num[x];
	int arry[] = {2,0};
	int n1;
	int nDigits = bi.length();
	//int i;
	__asm {
		mov ecx, nDigits
		mov eax, nDigits
		mov edx, 4
		mul edx
		mov ebx, eax
		sub ebx, 4
		push ebx
lpout:
		mov eax, asm_bi
		pop ebx
		mov edx, [eax+ebx]
		sub ebx, 4
		mov n1, edx
		push ebx
		push ecx
	}
	os << n1;
	__asm {
		pop ecx
		loop lpout
		pop ebx
	}
	delete[] asm_bi;
	asm_bi = NULL;
	return os;
}
void bigint::pushback(int n)
{
	this->num.push_back(n);
}

bigint::bigint(char* chr_arr)
{
	this->equals(chr_arr);
}